<?php
/*
 * @Description: 支付宝支付类
 * @Author: QianLong
 * @Date: 2019-09-27 16:34:02
 * @LastEditors    : QianLong
 * @LastEditTime   : 2021-05-08 17:34:46
 */

namespace app\common\service;

use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Util\ResponseChecker;
use app\common\service\alipay\Options;
use app\lib\exception\ApiException;

class Alipay extends Options
{
    /**
     * PC支付
     * @param array $orderData
     * @param string $notify_url
     * @param string $return_url
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-04-02 16:52:58
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-04-02 16:52:58
     */
    public function payForPc(array $orderData, string $return_url, string $notify_url = null)
    {
        if (!isset($orderData['out_trade_no']) || empty($orderData['out_trade_no'])) {
            throw new ApiException("缺少商户单号");
        }
        if (!isset($orderData['total_amount']) || empty($orderData['total_amount'])) {
            throw new ApiException("缺少金额");
        }
        if (!isset($orderData['subject']) || empty($orderData['subject'])) {
            throw new ApiException("缺少订单标题");
        }
        try {
            if (!empty($notify_url)) {
                $result = Factory::payment()->page()->asyncNotify($notify_url)->pay($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount'], $return_url);
            } else {
                $result = Factory::payment()->page()->pay($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount'], $return_url);
            }
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return $result->body;
            } else {
                throw new ApiException('调用失败，原因：' . $result->msg . ',' . $result->subMsg);
            }
        } catch (\Exception $e) {
            throw new ApiException('调用失败，' . $e->getMessage());
        }
    }
    /**
     * App支付
     * @param array $orderData
     * @param string $return_url
     * @param string $notify_url
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-05-07 12:07:27
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-05-07 12:07:27
     */
    public function payForApp(array $orderData, string $return_url, string $notify_url = null)
    {
        if (!isset($orderData['out_trade_no']) || empty($orderData['out_trade_no'])) {
            throw new ApiException("缺少商户单号");
        }
        if (!isset($orderData['total_amount']) || empty($orderData['total_amount'])) {
            throw new ApiException("缺少金额");
        }
        if (!isset($orderData['subject']) || empty($orderData['subject'])) {
            throw new ApiException("缺少订单标题");
        }
        try {
            if (!empty($notify_url)) {
                $result = Factory::payment()->app()->asyncNotify($notify_url)->pay($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount'], $return_url);
            } else {
                $result = Factory::payment()->app()->pay($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount'], $return_url);
            }
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return $result->body;
            } else {
                throw new ApiException('调用失败，原因：' . $result->msg . ',' . $result->subMsg);
            }
        } catch (\Exception $e) {
            throw new ApiException('调用失败，' . $e->getMessage());
        }
    }
    /**
     * 商家扫码支付
     * @param array $orderData
     * @param string $return_url
     * @param string $notify_url
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-05-07 17:48:24
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-05-07 17:48:24
     */
    public function scanPayQrcodePay(array $orderData, string $notify_url = null)
    {
        if (!isset($orderData['out_trade_no']) || empty($orderData['out_trade_no'])) {
            throw new ApiException("缺少商户单号：out_trade_no");
        }
        if (!isset($orderData['total_amount']) || empty($orderData['total_amount'])) {
            throw new ApiException("缺少金额：total_amount");
        }
        if (!isset($orderData['subject']) || empty($orderData['subject'])) {
            throw new ApiException("缺少订单标题：subject");
        }
        if (!isset($orderData['auth_code']) || empty($orderData['auth_code'])) {
            throw new ApiException("缺少支付授权码：auth_code");
        }
        try {
            if (!empty($notify_url)) {
                $result = Factory::payment()->FaceToFace()->asyncNotify($notify_url)->pay($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount'], $orderData['auth_code']);
            } else {
                $result = Factory::payment()->FaceToFace()->pay($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount'], $orderData['auth_code']);
            }
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return $result->body;
            } else {
                throw new ApiException('调用失败，原因：' . $result->msg . ',' . $result->subMsg);
            }
        } catch (\Exception $e) {
            throw new ApiException('调用失败，' . $e->getMessage());
        }
    }
    /**
     * 用户扫码支付
     * @param array $orderData
     * @param string $return_url
     * @param string $notify_url
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-05-07 17:48:24
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-05-07 17:48:24
     * @doc:https://opendocs.alipay.com/apis/api_1/alipay.trade.precreate
     */
    public function createPayQrcodePay(array $orderData, string $notify_url = null)
    {
        if (!isset($orderData['out_trade_no']) || empty($orderData['out_trade_no'])) {
            throw new ApiException("缺少商户单号：out_trade_no");
        }
        if (!isset($orderData['total_amount']) || empty($orderData['total_amount'])) {
            throw new ApiException("缺少金额：total_amount");
        }
        if (!isset($orderData['subject']) || empty($orderData['subject'])) {
            throw new ApiException("缺少订单标题：subject");
        }
        $options = [];
        if (isset($orderData['seller_id']) && !empty($orderData['seller_id'])) {
            $options['seller_id'] = $orderData['seller_id'];
        }
        if (isset($orderData['body']) && !empty($orderData['body'])) {
            $options['body'] = $orderData['body'];
        }
        if (isset($orderData['timeout_express']) && !empty($orderData['timeout_express'])) {
            $options['timeout_express'] = $orderData['timeout_express'];
        }
        if (isset($orderData['merchant_order_no']) && !empty($orderData['merchant_order_no'])) {
            $options['merchant_order_no'] = $orderData['merchant_order_no'];
        }
        // 公用回传参数，如果请求时传递了该参数，则返回给商户时会回传该参数。支付宝只会在同步返回（包括跳转回商户网站）和异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝。
        if (isset($orderData['passback_params']) && !empty($orderData['passback_params'])) {
            $options['passback_params'] = $orderData['passback_params'];
        }
        try {
            if (!empty($notify_url)) {
                $result = Factory::payment()->FaceToFace()->asyncNotify($notify_url)->batchOptional($options)->precreate($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount']);
            } else {
                $result = Factory::payment()->FaceToFace()->batchOptional($options)->precreate($orderData['subject'], $orderData['out_trade_no'], $orderData['total_amount']);
            }
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return $result->body;
            } else {
                throw new ApiException('调用失败，原因：' . $result->msg . ',' . $result->subMsg);
            }
        } catch (\Exception $e) {
            throw new ApiException('调用失败，' . $e->getMessage());
        }
    }
    /**
     * 退款
     * @param array $orderData
     * @param string $return_url
     * @param string $notify_url
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-05-07 17:25:05
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-05-07 17:25:05
     */
    public function refund(array $orderData)
    {
        if (!isset($orderData['trade_no']) || empty($orderData['trade_no'])) {
            throw new ApiException("缺少支付宝交易号：trade_no");
        }
        if (!isset($orderData['refund_amount']) || empty($orderData['refund_amount'])) {
            throw new ApiException("缺少需要退款的金额：refund_amount");
        }
        $options = [];
        if (isset($orderData['reason']) && !empty($orderData['reason'])) {
            $options['refund_reason'] = $orderData['reason'];
        }
        if (isset($orderData['currency']) && !empty($orderData['currency'])) {
            $options['refund_currency'] = $orderData['currency'];
        }
        if (isset($orderData['out_request_no']) && !empty($orderData['out_request_no'])) {
            $options['out_request_no'] = $orderData['out_request_no'];
        }
        try {
            $result = Factory::payment()->common()->batchOptional($options)->refund($orderData['trade_no'], $orderData['refund_amount']);
            $responseChecker = new ResponseChecker();
            //3. 处理响应或异常
            if ($responseChecker->success($result)) {
                return $result->body;
            } else {
                throw new ApiException('调用失败，原因：' . $result->msg . ',' . $result->subMsg);
            }
        } catch (\Exception $e) {
            throw new ApiException('调用失败，' . $e->getMessage());
        }
    }
    /**
     * 转帐到支付宝
     * @param array $orderData
     * @param string $remark
     * @param boolean $isRedPacket
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-05-07 17:02:19
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-05-07 17:02:19
     */
    public function transfer(array $orderData, $remark = '', $isRedPacket)
    {
        if (!isset($orderData['out_trade_no']) || empty($orderData['out_trade_no'])) {
            throw new ApiException("缺少商户单号");
        }
        if (!isset($orderData['total_amount']) || empty($orderData['total_amount'])) {
            throw new ApiException("缺少金额");
        }
        if (!isset($orderData['subject']) || empty($orderData['subject'])) {
            throw new ApiException("缺少标题");
        }
        if (!isset($orderData['alipay']) || empty($orderData['alipay'])) {
            throw new ApiException("缺少支付宝账号：alipay");
        }
        if (!isset($orderData['name']) || empty($orderData['name'])) {
            throw new ApiException("缺少支付宝账户姓名：name");
        }
        try {
            $bizParams = [
                "order_title" => $orderData['subject'],
                "out_biz_no" => $orderData['out_trade_no'],
                "trans_amount" => $orderData['total_amount'],
                "payee_info" => ["identity" => $orderData['alipay'], "identity_type" => 'ALIPAY_LOGON_ID', "name" => $orderData['name']],
                "remark" => $remark,
                "product_code" => ($isRedPacket) ? "STD_RED_PACKET" : "TRANS_ACCOUNT_NO_PWD",
                "biz_scene" => "DIRECT_TRANSFER"
            ];
            $result = Factory::util()->generic()->execute('alipay.fund.trans.uni.transfer', null, $bizParams);
            if ($result->code == 10000 || $result->code == '10000') {
                $array = json_decode($result->httpBody,true)['alipay_fund_trans_uni_transfer_response'];
                // $array['order_id'] 支付宝转账订单号
                // $array['out_biz_no'] 商户订单号
                // (可选) $array['pay_fund_order_id'] 支付宝支付资金流水号
                // $array['trans_date'] 订单支付时间，格式为yyyy-MM-dd HH:mm:ss
                // (可选) $array['status'] 转账单据状态。SUCCESS：成功；FAIL：失败（具体失败原因请参见error_code以及fail_reason返回值）；DEALING：处理中；REFUND：退票；
                return $array;
            }
            throw new ApiException('打款失败，原因：' . $result->msg . ',' . $result->subMsg);
        } catch (\Exception $e) {
            throw new ApiException('调用失败，' . $e->getMessage());
        }
    }
}
